home *** CD-ROM | disk | FTP | other *** search
/ Almathera Ten Pack 3: CDPD 3 / Almathera Ten on Ten - Disc 3: CDPD3.iso / scope / 026-050 / scopedisk47 / ls22 / ls.c < prev    next >
C/C++ Source or Header  |  1995-03-18  |  25KB  |  930 lines

  1. /* --------------------------------------------------------------------- *
  2.   LS.C -- an "improved" directory listing utility to replace the
  3.   AmigaDOS DIR and LIST commands.
  4.  
  5.   V1.0    August 1986 Written from scratch by Justin V. McCormick.
  6.   V2.0  November 1988 Revised for Lattice 5.0 and made 1.3 compatible.
  7.   V2.1  December 1988 Minor size reduction, fixed a few bugs from 2.0.
  8.   V2.2  December 1988 Fixed status return and multiple wildcard pathnames.
  9.  
  10. Notice:
  11.  
  12.   This program is placed in the public domain with the understanding
  13. that the author makes no claims or guarantees with regard to its
  14. suitability for any given application, and that the author assumes no
  15. responsibility for damages incurred by its usage.  Any resemblance
  16. of this program to any other program, either living or dead, is
  17. purely coincidental.
  18.  
  19.   Feel free to borrow this code and make millions of dollars from its
  20. sale or commercial use, but please give credit where credit is due.
  21.  
  22. Synopsis:
  23.  
  24.   Features adaptive columnar listing, versatile sort options,
  25. UNIX-style pattern matching, recursive subdirectory listing, etc!
  26.  
  27. Usage:
  28.     ls [options] [path1] [path2] ...
  29.  
  30. Options:
  31.     -?    Help!
  32.     -c    Show file comment info, -c implies -l
  33.     -d    Show directory names only
  34.     -f    Show filenames only
  35.     -l      Long verbose listing showing filesizes and dates
  36.     -n    No sort, just spit them out in the order ExNext() returns
  37.     -r    Reverse sort direction
  38.     -s    Sorted by size smallest to largest
  39.     -t    Sorted by date oldest to newest
  40.     -R    Recursive descent of subdirectories
  41.  
  42.   All arguments are optional.  Default is to give short columnar listing,
  43. sorted alphabetically, using the current directory.  Alphabetizing is case
  44. insensitive.
  45.  
  46.   Patterns may be matched in the given names, using the UNIX-style '*'
  47. to wildcard any number of characters, and '?' to wildcard a single
  48. character.  If you need to specify a pathname with spaces in it like
  49. "Wombat Soup", you need to put quotes around it.  LS can process up to 30
  50. separate pathname patterns in one command line.
  51.  
  52. Bugs:
  53.  
  54.   Redirecting the shortlist output to PRT: gives undesirable results,
  55. since I am using relative cursor positioning commands to format the
  56. screen output.  I thought about using an array to store a virtual
  57. screen, but my primary goals were to keep the size down and display
  58. speed at a maxiumum.  Also, LS cannot pattern match devices (like "dh*:")
  59. or support multiple levels of pattern matching (like "dh0:?/L*.info").
  60. This would involve another level of recursion and groking the Device List.
  61.  
  62. Changes From 1.0 to 2.0:
  63.  
  64.  o Source code prototyped, linted, traced, optimized, tweaked, etc.
  65.  o Made resident ("pseudo-pure") by linking with cres.o from LC 5.0.
  66.  o High-volume routines recoded in assembly (lssup.a).
  67.  o Now handles multiple paths/files on a command line, up to 30.
  68.  o New sort flags, including no sort.
  69.  o Enhanced wildcards, understands complex *.?*.* expressions now.
  70.  o More efficient ExNext() performance, less ram used for recursion.
  71.  o SIGBREAKF_CTRL_C signal (Ctrl-C) cleanly aborts at any point now.
  72.  o Command line parser handles quoted pathnames now (LC 5.0 benefit).
  73.  o Short listing finally auto-adjusts to new console window sizes!
  74.  o Pen color escape codes bypassed when redirecting long output.
  75.  o Sorting by size or date is also subsorted alphabetically now.
  76.  o Long listing shows new 1.3 file attributes, plus comment indicator.
  77.  o File dates are now in international format, YY-MM-DD.
  78.  o Fixed listings with files datestamped after 99-12-31 (overflow).
  79.  o Fixed listings with files datestamped before 78-01-01 (time < 0).
  80.  
  81. Changes From 2.0 to 2.1
  82.  
  83.  o Fixed the show comment feature, a last minute bug in 2.0.
  84.  o Fixed the "Unknown option ''" message problem.
  85.  o Optimized the assembly branches, reduced code size another few bytes.
  86.  
  87. Changes From 2.1 to 2.2
  88.  
  89.  o Fixed erroneous Status returns.
  90.  o Fixed bug with multiple wildcarded pathnames.
  91.  o Compiled with LC 5.0 Patch 3 and CAPE 2.0, saved another 46 bytes.
  92.  o Eliminated an extra stpcpy(), saved another few bytes.
  93.  
  94. * --------------------------------------------------------------------- */
  95.  
  96. /* Don't use __builtin for a minor savings in size */
  97. #define strlen strlen
  98.  
  99. /* Pass things using registers */
  100. #define _PARM __regargs
  101.  
  102. #include "ls.h"
  103.  
  104. /* Structure used to hold file info in a linked list */
  105. struct FibEntry
  106. {
  107.   struct FibEntry *NextFib;
  108.   struct FibEntry *LastFib;
  109.   struct FileInfoBlock *Fibp;
  110. };
  111.  
  112. /* Externs from lssup.a */
  113. /*lint +fva2 */
  114. extern int  __stdargs asprintf (char *, char *,...);
  115. /*lint -fva2 */
  116.  
  117. extern void __stdargs SortFibs (long, long, struct FibEntry *);
  118. extern long __stdargs iswild (char *);
  119. extern long __stdargs wildmatch (char *, char *);
  120. extern char *__stdargs FibFileDate (struct DateStamp *);
  121. extern void __stdargs GetWinBounds (long *, long *);
  122.  
  123.  
  124. /* Local CODE */
  125. struct FibEntry *AllocFib (void);
  126. struct FibEntry *GetDir (struct FileLock *, struct FileInfoBlock *);
  127. void CleanUp (char *, long);
  128. void ColorPen2 (void);
  129. void CursorOff (void);
  130. void CursorOn (void);
  131. void main (int, char **);
  132. void ResetPen (void);
  133. void TestBreak (void);
  134. void Usage (void);
  135. void _PARM DirIt (struct FileLock *, char *);
  136. void _PARM FreeAllFibs (struct FibEntry *);
  137. void _PARM FreeFib (struct FibEntry *);
  138. void _PARM LListDir (struct FibEntry *);
  139. void _PARM LListEntry (struct FileInfoBlock *);
  140. void _PARM LongList (long *, long *, struct FibEntry *);
  141. void _PARM PagePrompt (long);
  142. void _PARM SListDir (struct FibEntry *);
  143. void _PARM WCHR (char *);
  144. void _PARM WSTR (char *);
  145.  
  146. struct FileHandle *Out = 0L;
  147. struct FileHandle *In = 0L;
  148. struct FileLock *lockp = 0L;
  149. struct FileInfoBlock *GFibp = 0L;
  150.  
  151. long BREAKFLAG = 0;
  152. long CONSOLE = 0;
  153. long DIRFILEFLAG = 0;
  154. long LISTALL = 0;
  155. long LONGLIST = 0;
  156. long NOSORTFLAG = 0;
  157. long NOTEFLAG = 0;
  158. long PATHNAMED = 0;
  159. long REVFLAG = 0;
  160. long WILDCARD = 0;
  161.  
  162. long dircount = 0;
  163. long errstat = 0;
  164. long filecount = 0;
  165. long maxnamlen = 0;
  166. long sortkey = 0;
  167.  
  168. long CurWinRows = 20L;
  169. long CurWinCols = 77L;
  170.  
  171. char filename[160];
  172. char pattern[160];
  173. char workstr[160];
  174.  
  175. static char Author[] = "\23333mLS 2.2\2330m by Justin V. McCormick 1988";
  176. static char usage[] = "\nUsage: ls [-cdflnrstR] [path1] [path2] ...\n";
  177.  
  178. /* -------------------------------------------------------------------- */
  179. void main (argc, argv)
  180.   int argc;
  181.   char **argv;
  182. {
  183.   struct Process *procp;
  184.   long cnt, i;
  185.  
  186.   if (argc == 0)            /* son of Workbench -- no go! */
  187.     exit (0);
  188.  
  189. /* Grab FileHandles for input and output to console (or redirection file) */
  190.   In = Input ();
  191.   Out = Output ();
  192.   CONSOLE = IsInteractive(Out) == 0L ? 0 : 1; /* Is this console output? */
  193.  
  194. /* Allocate a global FileInfoBlock for ExNext() */
  195.   if ( (GFibp = (struct FileInfoBlock *)AllocMem((long)sizeof(struct FileInfoBlock), MEMF_PUBLIC | MEMF_CLEAR)) == 0L)
  196.     CleanUp("No RAM?", 103L);
  197.  
  198. /* Parse command line arguments <ugh> */
  199.   cnt = 1;
  200.   if (argc >= 2)
  201.   {
  202.     if (argv[1][0] == '-')
  203.     {
  204.       cnt++;
  205.       for (i = strlen(argv[1]) - 1; i > 0; i--)
  206.       {
  207.         switch (argv[1][i])
  208.         {
  209.       case 'c': 
  210.         LONGLIST = 1;
  211.         NOTEFLAG = 1;
  212.         break;
  213.           case 'd':
  214.             DIRFILEFLAG |= 1;
  215.             break;
  216.           case 'f':
  217.             DIRFILEFLAG |= 2;
  218.             break;
  219.       case 'l': 
  220.         LONGLIST = 1;
  221.         break;
  222.       case 'n':
  223.         NOSORTFLAG = 1;
  224.         break;
  225.       case 'r':
  226.         REVFLAG = 1;
  227.         break;
  228.       case 's':
  229.         sortkey = 1;
  230.         break;
  231.       case 't': 
  232.         sortkey = 2;
  233.         break;
  234.       case 'R': 
  235.         LISTALL = 1;
  236.         break;
  237.       case '?': 
  238.         Usage ();
  239.         break;
  240.       default:
  241.         pattern[0] = argv[1][i];
  242.         pattern[1] = 0;
  243.         (void) asprintf (workstr, "Unknown option \'%s\'\n", pattern);
  244.         WSTR (workstr);
  245.         Usage ();
  246.         break;
  247.     }
  248.       }
  249.     }
  250.   }
  251.  
  252. /* Clean up the state flags */
  253.   if ( (argc - cnt) > 1)
  254.     LISTALL |= 2;
  255.  
  256.   if (DIRFILEFLAG == 0)
  257.     DIRFILEFLAG = 3;
  258.  
  259. /* Loop through the remaining args now */
  260.   do
  261.   {
  262.     PATHNAMED = 0;
  263.     if (cnt < argc)
  264.     {
  265.       (void) stpcpy (pattern, argv[cnt]);
  266.       PATHNAMED = 1;
  267.     }
  268.  
  269.     if (PATHNAMED)            /* If user specified a pathname    */
  270.     {
  271.       WILDCARD = iswild (pattern);     /* check for wildcards         */
  272.  
  273.       if (WILDCARD)            /* If wildcards, separate    */
  274.       {                    /* pattern from pathname    */
  275.         filename[0] = (BYTE) 0;
  276.         for (i = strlen (pattern) - 1; i >= 0; i--)
  277.         {
  278.           if (pattern[i] == '/' || pattern[i] == ':')
  279.           {
  280.             i++;
  281.         (void) strncpy (filename, pattern, i);
  282.         filename[i] = (BYTE) 0;
  283.         (void) stpcpy (pattern, &pattern[i]);
  284.         break;
  285.           }
  286.         }
  287. /* Disallow wildcards in pathname */
  288.         if (iswild (filename))
  289.           CleanUp ("Sorry, can't pattern match paths", 5L);
  290.       }
  291.       else                /* No wildcards, use filename as is */
  292.       {
  293.         (void) stpcpy (filename, pattern);
  294.       }
  295.  
  296. /* If the user specified a pathname, try to grab a FileLock on it */
  297. /* Discard trailing slash if silly Joe User put one there */
  298.       if (filename[1] != 0 && filename[strlen (filename) - 1] == '/')
  299.         filename[strlen (filename) - 1] = (BYTE) 0;
  300.  
  301.       lockp = Lock (filename, ACCESS_READ);
  302.  
  303.       if (!lockp)            /* Can't Lock it!         */
  304.       {
  305.         errstat = IoErr();
  306.         (void) strcat (filename, " not found");
  307.         CleanUp (filename, (long)errstat);
  308.       }
  309.     }
  310.     else
  311.     {
  312. /*
  313.  * If no filename was specified, steal Lock on current directory from
  314.  * CLI process task info.  We durn well better get something useful back;
  315.  * we don't do any error checking on the stolen Lock.
  316.  */
  317.       procp = (struct Process *) FindTask (0L);
  318.       lockp = (struct FileLock *)procp->pr_CurrentDir;
  319.       filename[0] = 0;            /* Tell DirIt() to use current dir */
  320.     }
  321.  
  322. /* Get the directory for this path, display it */
  323.     DirIt (lockp, filename);
  324.  
  325. /* Release the lock, bump our arg counter */
  326.     if (lockp != 0 && PATHNAMED != 0)
  327.       UnLock (lockp);
  328.     lockp = 0L;
  329.     cnt++;
  330.  
  331.     if (cnt < argc)
  332.       WCHR("\n");
  333.   } while (cnt < argc && BREAKFLAG == 0);
  334.  
  335.   CleanUp ("", 0L);
  336. }
  337.  
  338. /* -------------------------------------------------------------------- */
  339. /* Deallocate and close everything                     */
  340. /* -------------------------------------------------------------------- */
  341. void CleanUp (exit_msg, exit_status)
  342.   char *exit_msg;
  343.   long exit_status;
  344. {
  345.   if (lockp && PATHNAMED)
  346.     UnLock (lockp);
  347.  
  348.   if (GFibp != 0L)
  349.     FreeMem(GFibp, (long)sizeof(struct FileInfoBlock));
  350.  
  351.   if (exit_status)
  352.   {
  353.     (void) asprintf (workstr, "ls: %s, Error #%ld\n", exit_msg, exit_status);
  354.     WSTR (workstr);
  355.   }
  356.   exit ((int) exit_status);
  357. }
  358.  
  359. /* -------------------------------------------------------------------- */
  360. void _PARM DirIt (lockp, dirname)
  361.   struct FileLock *lockp;
  362.   char *dirname;
  363. {
  364.   struct FileLock *tlockp;
  365.   struct FibEntry *fibheadp;
  366.   struct FibEntry *tfibp;
  367.   char *subdir;
  368.   long strsize;
  369.  
  370. /* Try to fill FileInfoBlock, bomb if not readable for some reason */
  371.   if (!Examine (lockp, GFibp))
  372.   {
  373.     (void) asprintf (workstr, "Can't examine file or directory\n");
  374.     WSTR (workstr);
  375.     return;
  376.   }
  377.  
  378. /* Put directory header if this is a recursive listing */
  379.   if (dirname[0] && LISTALL > 0)
  380.   {
  381.     if (CONSOLE != 0)
  382.      (void)asprintf(workstr, "\23330;41m %s \2330m\n", dirname);
  383.     else
  384.      (void)asprintf(workstr, "%s\n", dirname);
  385.     WSTR(workstr);
  386.   }
  387.  
  388. /* If this is a single file list it verbosely */
  389.   if (GFibp->fib_EntryType < 0 && (DIRFILEFLAG & 2) != 0)
  390.   {
  391.     LListEntry (GFibp);
  392.   }
  393.   else
  394.   {
  395. /* Otherwise do a directory     */
  396. /* Allocate and initialize a FibEntry head node */
  397.     if ( (fibheadp = GetDir (lockp, GFibp)) != 0L && BREAKFLAG == 0)
  398.     {
  399.       if (NOSORTFLAG == 0)
  400.         SortFibs ((long)sortkey, (long)REVFLAG, fibheadp);
  401.  
  402.       if (LONGLIST == 0)
  403.     SListDir (fibheadp);
  404.       else
  405.     LListDir (fibheadp);
  406.  
  407.       if ( (LISTALL & 1) != 0)
  408.       {
  409.         tfibp = fibheadp;
  410.     do
  411.     {
  412.       if (tfibp->Fibp->fib_EntryType > 0)
  413.       {
  414.         strsize = (strlen (dirname) + strlen (tfibp->Fibp->fib_FileName) + 2);
  415.         subdir = (char *) AllocMem ((long)strsize, 0L);
  416.         if (strlen (dirname) != 0)
  417.         {
  418.           (void) stpcpy (subdir, dirname);
  419.           if (dirname[strlen (dirname) - 1] != ':')
  420.         (void) strcat (subdir, "/");
  421.         }
  422.         (void) strcat (subdir, tfibp->Fibp->fib_FileName);
  423.         tlockp = Lock (subdir, ACCESS_READ);
  424.         if (tlockp == 0L)
  425.         {
  426.           WSTR (subdir);
  427.           WSTR (" -- can't lock it!\n");
  428.           break;
  429.         }
  430.         else
  431.         {
  432.           WCHR ("\n");        /* Put a blank line between directories */
  433.           DirIt (tlockp, subdir);
  434.           UnLock (tlockp);
  435.           FreeMem (subdir, (long)strsize);
  436.         }
  437.       }
  438.       tfibp = tfibp->NextFib;
  439.     } while (tfibp != fibheadp && BREAKFLAG == 0);
  440.       }
  441.     }
  442. /* Clean up */
  443.     FreeAllFibs (fibheadp);
  444.   }
  445. }
  446.  
  447. /* -------------------------------------------------------------------- */
  448. /* Allocate and fill a linked list of FileInfoBlocks             */
  449. /* -------------------------------------------------------------------- */
  450. struct FibEntry *GetDir (lockp, fibp)
  451.   struct FileLock *lockp;
  452.   struct FileInfoBlock *fibp;
  453. {
  454.   long nextstat;
  455.   long tempnamlen;
  456.   struct FibEntry *tfibp;
  457.   struct FibEntry *headfib;
  458.  
  459.   maxnamlen = dircount = filecount = 0L;
  460.   headfib = 0L;
  461.  
  462.   do
  463.   {
  464.     TestBreak();
  465.     if (BREAKFLAG != 0)
  466.       return(headfib);
  467.     nextstat = ExNext (lockp, fibp);
  468.  
  469.     if (nextstat != 0)    /* We got something */
  470.     {
  471. /* See if it matches our pattern */
  472.       if (!WILDCARD || wildmatch (fibp->fib_FileName, pattern))
  473.       {
  474.  
  475. /* Bump count of files or directories */
  476.     if (fibp->fib_EntryType > 0)
  477.         {
  478.           if ((DIRFILEFLAG & 1) != 0)
  479.             dircount++;
  480.           else
  481.             goto ALLOCFIB;
  482.         }
  483.         else
  484.         {
  485.           if ((DIRFILEFLAG & 2) != 0)
  486.             filecount++;
  487.           else
  488.             continue;
  489.         }
  490.  
  491. /* See if this is the longest filename for later use in listing */
  492.     tempnamlen = strlen (fibp->fib_FileName);
  493.     if (tempnamlen > maxnamlen)
  494.       maxnamlen = tempnamlen;
  495.  
  496.         ALLOCFIB:
  497. /* Allocate another FibEntry to put the info in */
  498.         if (headfib == 0L)
  499.         {
  500.           headfib = AllocFib();
  501.           if (headfib == 0L)
  502.             return(headfib);
  503.           headfib->NextFib = headfib;
  504.           headfib->LastFib = headfib;
  505.           *(headfib->Fibp) = *(fibp);
  506.           tfibp = headfib;
  507.         }
  508.         else
  509.         {
  510.       tfibp->NextFib = AllocFib ();
  511.       if (tfibp->NextFib == 0L)
  512.         return(0L);
  513.  
  514. /* Copy FIB contents to next entry for ExNext to work with */
  515.       *(tfibp->NextFib->Fibp) = *(fibp);
  516.  
  517. /* Link it into the list */
  518.       tfibp->NextFib->LastFib = tfibp;
  519.       tfibp = tfibp->NextFib;
  520.       tfibp->NextFib = headfib;
  521.     }
  522.       }
  523.     }
  524.   } while (nextstat);
  525.  
  526. /* Return TRUE if entries found, else print message and return FALSE */
  527.   if ( (dircount + filecount) != 0)
  528.   {
  529.     return (headfib);
  530.   }
  531.   else
  532.   {
  533.     if (WILDCARD == 0 && DIRFILEFLAG == 3)
  534.       WSTR ("Volume or directory is empty.\n");
  535.     else
  536.       WSTR ("No match.\n");
  537.     return (0L);
  538.   }
  539. }
  540.  
  541. /* -------------------------------------------------------------------- */
  542. /* List a FibEntry list in a compact fashion                 */
  543. /* -------------------------------------------------------------------- */
  544. void _PARM SListDir (fibheadp)
  545.   struct FibEntry *fibheadp;
  546. {
  547.   struct FibEntry *tfibp;
  548.   long tabsize;
  549.   long maxtab;
  550.   long totrows;
  551.   long maxwinrow;
  552.   long colcnt;
  553.   long rowcnt;
  554.   long tabcnt;
  555.   long pagecnt = 1;
  556.  
  557.   CursorOff ();        /* Turn the cursor off since it will blink anyway */
  558.   GetWinBounds(&CurWinCols, &CurWinRows);
  559.  
  560.   tfibp = fibheadp;
  561.   tabcnt = rowcnt = colcnt = 0;
  562.  
  563.   tabsize = maxnamlen + 2;
  564.   if (CurWinCols < tabsize)
  565.     maxtab = 1;
  566.   else
  567.     maxtab = CurWinCols / tabsize;
  568.   maxwinrow = CurWinRows - 3;
  569.   if (maxwinrow <= 0)
  570.     maxwinrow = 1;
  571.   totrows = (dircount + filecount) / maxtab;
  572.   if ((dircount + filecount) % maxtab != 0)
  573.     totrows++;
  574.  
  575.   do
  576.   {
  577.     if (tfibp->Fibp->fib_EntryType > 0)
  578.     {
  579.       if ( (DIRFILEFLAG & 1) == 0)
  580.         goto GETNEXTFIB;
  581.       else
  582.         ColorPen2 ();
  583.     }
  584.     if (tabcnt)
  585.       (void) asprintf (workstr, "\233%ldC", (long)tabcnt);
  586.     else
  587.       workstr[0] = (BYTE) 0;
  588.     (void) strcat (workstr, tfibp->Fibp->fib_FileName);
  589.     (void) strcat (workstr, "\n");
  590.     WSTR (workstr);
  591.     if (tfibp->Fibp->fib_EntryType > 0)
  592.       ResetPen ();
  593.     rowcnt++;
  594.  
  595.     if (rowcnt == maxwinrow || rowcnt == totrows)
  596.     {
  597.       colcnt++;                /* Start a new column         */
  598. /* Check to see if we have used the last column up and are about to run
  599.  * off the screen entirely.  If so, give the user a chance to read it first.
  600.  */
  601.       if (colcnt == maxtab && rowcnt == maxwinrow && CONSOLE != 0)
  602.       {
  603.         if (maxwinrow > 1)
  604.         {
  605.          ++pagecnt;            /* Advance page number count    */
  606.      PagePrompt (pagecnt);        /* Print it, wait for user    */
  607.     }
  608.     totrows -= maxwinrow;
  609.     colcnt = tabcnt = rowcnt = 0L;
  610.       }
  611.       else    /* Just move over one row and back up to the top */
  612.       {
  613.     (void) asprintf (workstr, "\233%ldA", (long)rowcnt);
  614.     WSTR (workstr);
  615.     tabcnt += tabsize;
  616.     rowcnt = 0L;
  617.       }
  618.     }
  619.     GETNEXTFIB:
  620.     tfibp = tfibp->NextFib;
  621.   } while (tfibp != fibheadp);
  622.  
  623.   if (totrows - rowcnt > 0)        /* Cursor down till level with     */
  624.   {                    /* lowest line on screen     */
  625.     (void) asprintf (workstr, "\233%ldE", (long)(totrows - rowcnt));
  626.     WSTR (workstr);
  627.   }
  628.   CursorOn ();
  629. }
  630.  
  631. /* -------------------------------------------------------------------- */
  632. /* Reset character color to default Pen1 colors             */
  633. /* -------------------------------------------------------------------- */
  634. void ResetPen ()
  635. {
  636.   if (CONSOLE != 0)
  637.     WSTR ("\2330m");
  638. }
  639.  
  640. /* -------------------------------------------------------------------- */
  641. /* Turn the cursor on                            */
  642. /* -------------------------------------------------------------------- */
  643. void CursorOn ()
  644. {
  645.   if (CONSOLE != 0)
  646.     WSTR ("\233 p");
  647. }
  648.  
  649. /* -------------------------------------------------------------------- */
  650. /* Turn the cursor off for faster text output                 */
  651. /* -------------------------------------------------------------------- */
  652. void CursorOff ()
  653. {
  654.   if (CONSOLE != 0)
  655.     WSTR ("\2330 p");
  656. }
  657.  
  658. /* -------------------------------------------------------------------- */
  659. /* Make Pen2 <usually yellow/orange> the current charcter color     */
  660. /* -------------------------------------------------------------------- */
  661. void ColorPen2 ()
  662. {
  663.   if (CONSOLE != 0)
  664.     WSTR ("\23333m");
  665. }
  666.  
  667. /* -------------------------------------------------------------------- */
  668. /* Prompt the user to hit return, wait till return is hit         */
  669. /* -------------------------------------------------------------------- */
  670. void _PARM PagePrompt (page)
  671.   long page;
  672. {
  673.   WSTR ("\2337m -- MORE -- Press Return: \2330m");
  674.   (void) Read (In, workstr, 1L);
  675.   (void) asprintf (workstr, "\233F\233K\2334;33mPage %ld:\2330m\n", (long)page);
  676.   WSTR (workstr);
  677. }
  678.  
  679. /* -------------------------------------------------------------------- */
  680. /* List a directory in a verbose informative manner             */
  681. /* -------------------------------------------------------------------- */
  682. void _PARM LListDir (fibheadp)
  683.   struct FibEntry *fibheadp;
  684. {
  685.   long totblocks = 0L;
  686.   long totbytes = 0L;
  687.  
  688.   CursorOff ();
  689.   LongList (&totblocks, &totbytes, fibheadp);
  690.  
  691.   (void) asprintf (workstr, "Dirs:%-3ld Files:%-4ld Blocks:%-5ld Bytes:%-8ld\n",
  692.       (long)dircount, (long)filecount, totblocks, totbytes);
  693.   WSTR (workstr);
  694.   CursorOn ();
  695. }
  696.  
  697. /* -------------------------------------------------------------------- */
  698. void _PARM LongList (totblocks, totbytes, fibheadp)
  699.   long *totblocks, *totbytes;
  700.   struct FibEntry *fibheadp;
  701. {
  702.   struct FibEntry *tfibp;
  703.  
  704.   tfibp = fibheadp;
  705.   do
  706.   {
  707.     LListEntry (tfibp->Fibp);
  708.     if (tfibp->Fibp->fib_EntryType < 0)
  709.     {
  710.       *totblocks += tfibp->Fibp->fib_NumBlocks;
  711.       *totbytes += tfibp->Fibp->fib_Size;
  712.     }
  713.     tfibp = tfibp->NextFib;
  714.   } while (tfibp != fibheadp);
  715. }
  716.  
  717. /* -------------------------------------------------------------------- */
  718. /* Verbosely list a particular FibEntry                 */
  719. /* -------------------------------------------------------------------- */
  720. void _PARM LListEntry (fib)
  721.   struct FileInfoBlock *fib;
  722. {
  723.   long i, pmodes;
  724.   char *cp1;
  725.   char entry[160];
  726.  
  727.   pmodes = fib->fib_Protection & 0xff;
  728.   cp1 = stpcpy (entry, "chsparwed ");
  729.   for (i = 0; i < 4; i++)
  730.   {
  731.     if ((pmodes & (1 << i)) != 0)
  732.       entry[8 - i] = '-';
  733.   }
  734.   for (; i < 8; i++)
  735.   {
  736.     if ((pmodes & (1 << i)) == 0)
  737.       entry[8 - i] = '-';
  738.   }
  739.   if (fib->fib_Comment[0] == 0)
  740.     entry[0] = '-';
  741.  
  742.   cp1 = stpcpy (cp1, FibFileDate (&fib->fib_Date));
  743.   if (fib->fib_EntryType > 0)
  744.   {
  745.     if ( (DIRFILEFLAG & 1) == 0)
  746.       return;
  747.  
  748.     if (CONSOLE)
  749.       cp1 = stpcpy (cp1, "\23333m");
  750.     cp1 = stpcpy (cp1, "   Directory   ");
  751.     if (CONSOLE)
  752.       cp1 = strcat (cp1, "\2330m");
  753.   }
  754.   else
  755.     (void) asprintf (&entry[27], " %4ld %8ld ", fib->fib_NumBlocks, fib->fib_Size);
  756.   (void)strcat(entry, fib->fib_FileName);
  757.   (void)strcat(cp1, "\n");
  758.   WSTR (entry);
  759.  
  760.   if (NOTEFLAG != 0 && fib->fib_Comment[0] != 0)
  761.   {
  762.     if (CONSOLE)
  763.       (void)asprintf(entry, "\23333m/* %s */\2330m\n", fib->fib_Comment);
  764.     else
  765.       (void)asprintf(entry, "/* %s */\n", fib->fib_Comment);
  766.     WSTR (entry);
  767.   }
  768. }
  769.  
  770. #ifdef NOASM
  771. /* -------------------------------------------------------------------- */
  772. /* Calculate date based on DateStamp structure, return a string pointer */
  773. /* -------------------------------------------------------------------- */
  774. char *CalcDate (fib)
  775.   struct FileInfoBlock *fib;
  776. {
  777.   static long days[12] =
  778.   {
  779.     31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
  780.   };
  781.  
  782.   static char *months[12] =
  783.   {
  784.     "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  785.     "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
  786.   };
  787.   char datestr[25];
  788.   long i, mdays;
  789.   long day, hour;
  790.   long minute, sec;
  791.   long ldays;
  792.   long year;
  793.  
  794.   ldays = 1461L;
  795.   year = 78L;
  796.   day = fib->fib_Date.ds_Days;
  797.   minute = fib->fib_Date.ds_Minute;
  798.   sec = fib->fib_Date.ds_Tick / 50L;
  799.   year += (day / ldays) * 4L;
  800.   day %= ldays;
  801.  
  802.   while (day)
  803.   {
  804.     mdays = 365;
  805.     if ((year & 3) == 0)
  806.       mdays++;
  807.     if (day < mdays)
  808.       break;
  809.     day -= mdays;
  810.     year++;
  811.   }
  812.  
  813.   for (i = 0L, day++; i < 12; i++)
  814.   {
  815.     mdays = days[i];
  816.     if (i == 1 && (year & 3) == 0)
  817.       mdays++;
  818.     if (day <= mdays)
  819.       break;
  820.     day -= mdays;
  821.   }
  822.   hour = minute / 60;
  823.   minute -= hour * 60;
  824.   (void) asprintf (datestr, "%02ld-%s-%02ld %02ld:%02ld:%02ld ", day, (long)months[i], year, hour, minute, sec);
  825.   return (datestr);
  826. }
  827. #endif
  828.  
  829. /* -------------------------------------------------------------------- */
  830. /* Use AmigaDos to put a string on the stdout                 */
  831. /* -------------------------------------------------------------------- */
  832. void _PARM WSTR (tstring)
  833.   char *tstring;
  834. {
  835.   (void) Write (Out, tstring, (long) strlen (tstring));
  836. }
  837.  
  838. /* -------------------------------------------------------------------- */
  839. /* Use AmigaDos to put a character on the stdout             */
  840. /* -------------------------------------------------------------------- */
  841. void _PARM WCHR (ch)
  842.   char *ch;
  843. {
  844.   (void) Write (Out, ch, 1L);
  845. }
  846.  
  847. /* -------------------------------------------------------------------- */
  848. /* Check to see if the user hit ^C                     */
  849. /* -------------------------------------------------------------------- */
  850. void TestBreak ()
  851. {
  852.   unsigned long oldsig;
  853.  
  854.   oldsig = SetSignal (0L, SIGBREAKF_CTRL_C);
  855.   if ( (oldsig & SIGBREAKF_CTRL_C) != 0L)
  856.   {
  857.     WSTR ("\2330m\233 p**BREAK\n");
  858.     BREAKFLAG = 1;
  859.   }
  860. }
  861.  
  862. /* -------------------------------------------------------------------- */
  863. /* Explain how to use                             */
  864. /* -------------------------------------------------------------------- */
  865. void Usage ()
  866. {
  867.   WSTR (Author);
  868.   WSTR (usage);
  869.   WSTR (" c > Show comments\n");
  870.   WSTR (" d > Dirs only\n");
  871.   WSTR (" f > Files only\n");
  872.   WSTR (" l > Long listing\n");
  873.   WSTR (" n > No sort\n");
  874.   WSTR (" r > Reverse sort\n");
  875.   WSTR (" s > Sort by size\n");
  876.   WSTR (" t > Sort by date\n");
  877.   WSTR (" R > Recursive listing\n");
  878.   CleanUp ("", 0L);
  879. }
  880.  
  881. /* -------------------------------------------------------------------- */
  882. /* Allocate a FibEntry structure and associated FileInfoBlock         */
  883. /* -------------------------------------------------------------------- */
  884. struct FibEntry *AllocFib ()
  885. {
  886.   struct FibEntry *tfibp;
  887.  
  888.   tfibp = (struct FibEntry *) AllocMem \
  889. ((long)( sizeof (struct FibEntry) + sizeof(struct FileInfoBlock) ), 0L);
  890.   if (tfibp != 0L)
  891.   {
  892.     tfibp->Fibp = (struct FileInfoBlock *)((ULONG)tfibp + sizeof(struct FibEntry));
  893.   }
  894.   else
  895.     BREAKFLAG = 1;
  896.   return (tfibp);
  897. }
  898.  
  899. /* -------------------------------------------------------------------- */
  900. /* Free up memory allocated to a linked list of FibEntrys         */
  901. /* -------------------------------------------------------------------- */
  902. void _PARM FreeAllFibs (fibheadp)
  903.   struct FibEntry *fibheadp;
  904. {
  905.   struct FibEntry *fibp;
  906.   struct FibEntry *tfibp;
  907.  
  908.   if (fibheadp != 0)
  909.   {
  910.     fibp = fibheadp;
  911.     do
  912.     {
  913.       tfibp = fibp->NextFib;
  914.       FreeFib (fibp);
  915.       fibp = tfibp;
  916.     } while (tfibp != fibheadp);
  917.   }
  918. }
  919.  
  920. /* -------------------------------------------------------------------- */
  921. /* Deallocate a single FibEntry structure                 */
  922. /* -------------------------------------------------------------------- */
  923. void _PARM FreeFib (fibp)
  924.   struct FibEntry *fibp;
  925. {
  926.   if (fibp != 0L)
  927.     FreeMem (fibp, (long)(sizeof (struct FibEntry) + sizeof(struct FileInfoBlock)));
  928. }
  929.  
  930.